// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_BASE_DECRYPTOR_H_
#define MEDIA_BASE_DECRYPTOR_H_

#include <list>

#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "media/base/audio_buffer.h"
#include "media/base/media_export.h"

namespace media {

class AudioDecoderConfig;
class DecoderBuffer;
class VideoDecoderConfig;
class VideoFrame;

// Decrypts (and decodes) encrypted buffer.
//
// All methods are called on the (video/audio) decoder thread. Decryptor
// implementations must be thread safe when methods are called this way.
// Depending on the implementation callbacks may be fired synchronously or
// asynchronously.
class MEDIA_EXPORT Decryptor {
public:
    enum Status {
        kSuccess, // Decryption successfully completed. Decrypted buffer ready.
        kNoKey, // No key is available to decrypt.
        kNeedMoreData, // Decoder needs more data to produce a frame.
        kError, // Key is available but an error occurred during decryption.
        kStatusMax = kError
    };

    // TODO(xhwang): Unify this with DemuxerStream::Type.
    enum StreamType { kAudio,
        kVideo,
        kStreamTypeMax = kVideo };

    Decryptor();
    virtual ~Decryptor();

    // Indicates that a new key has been added to the ContentDecryptionModule
    // object associated with the Decryptor.
    typedef base::Callback<void()> NewKeyCB;

    // Registers a NewKeyCB which should be called when a new key is added to the
    // decryptor. Only one NewKeyCB can be registered for one |stream_type|.
    // If this function is called multiple times for the same |stream_type|, the
    // previously registered callback will be replaced. In other words,
    // registering a null callback cancels the originally registered callback.
    virtual void RegisterNewKeyCB(StreamType stream_type,
        const NewKeyCB& key_added_cb)
        = 0;

    // Indicates completion of a decryption operation.
    //
    // First parameter: The status of the decryption operation.
    // - Set to kSuccess if the encrypted buffer is successfully decrypted and
    //   the decrypted buffer is ready to be read.
    // - Set to kNoKey if no decryption key is available to decrypt the encrypted
    //   buffer. In this case the decrypted buffer must be NULL.
    // - Set to kError if unexpected error has occurred. In this case the
    //   decrypted buffer must be NULL.
    // - This parameter should not be set to kNeedMoreData.
    // Second parameter: The decrypted buffer.
    // - Only |data|, |data_size| and |timestamp| are set in the returned
    //   DecoderBuffer. The callback handler is responsible for setting other
    //   fields as appropriate.
    typedef base::Callback<void(Status,
        const scoped_refptr<DecoderBuffer>&)>
        DecryptCB;

    // Decrypts the |encrypted| buffer. The decrypt status and decrypted buffer
    // are returned via the provided callback |decrypt_cb|. The |encrypted| buffer
    // must not be NULL.
    // Decrypt() should not be called until any previous DecryptCB of the same
    // |stream_type| has completed. Thus, only one DecryptCB may be pending at
    // a time for a given |stream_type|.
    virtual void Decrypt(StreamType stream_type,
        const scoped_refptr<DecoderBuffer>& encrypted,
        const DecryptCB& decrypt_cb)
        = 0;

    // Cancels the scheduled decryption operation for |stream_type| and fires the
    // pending DecryptCB immediately with kSuccess and NULL.
    // Decrypt() should not be called again before the pending DecryptCB for the
    // same |stream_type| is fired.
    virtual void CancelDecrypt(StreamType stream_type) = 0;

    // Indicates completion of audio/video decoder initialization.
    //
    // First Parameter: Indicates initialization success.
    // - Set to true if initialization was successful. False if an error occurred.
    typedef base::Callback<void(bool)> DecoderInitCB;

    // Initializes a decoder with the given |config|, executing the |init_cb|
    // upon completion.
    virtual void InitializeAudioDecoder(const AudioDecoderConfig& config,
        const DecoderInitCB& init_cb)
        = 0;
    virtual void InitializeVideoDecoder(const VideoDecoderConfig& config,
        const DecoderInitCB& init_cb)
        = 0;

    // Helper structure for managing multiple decoded audio buffers per input.
    typedef std::list<scoped_refptr<AudioBuffer>> AudioFrames;

    // Indicates completion of audio/video decrypt-and-decode operation.
    //
    // First parameter: The status of the decrypt-and-decode operation.
    // - Set to kSuccess if the encrypted buffer is successfully decrypted and
    //   decoded. In this case, the decoded frame/buffers can be/contain:
    //   1) NULL, which means the operation has been aborted.
    //   2) End-of-stream (EOS) frame, which means that the decoder has hit EOS,
    //      flushed all internal buffers and cannot produce more video frames.
    //   3) Decrypted and decoded video frame or audio buffer.
    // - Set to kNoKey if no decryption key is available to decrypt the encrypted
    //   buffer. In this case the returned frame(s) must be NULL/empty.
    // - Set to kNeedMoreData if more data is needed to produce a video frame. In
    //   this case the returned frame(s) must be NULL/empty.
    // - Set to kError if unexpected error has occurred. In this case the
    //   returned frame(s) must be NULL/empty.
    // Second parameter: The decoded video frame or audio buffers.
    typedef base::Callback<void(Status, const AudioFrames&)> AudioDecodeCB;
    typedef base::Callback<void(Status,
        const scoped_refptr<VideoFrame>&)>
        VideoDecodeCB;

    // Decrypts and decodes the |encrypted| buffer. The status and the decrypted
    // buffer are returned via the provided callback.
    // The |encrypted| buffer must not be NULL.
    // At end-of-stream, this method should be called repeatedly with
    // end-of-stream DecoderBuffer until no frame/buffer can be produced.
    // These methods can only be called after the corresponding decoder has
    // been successfully initialized.
    virtual void DecryptAndDecodeAudio(
        const scoped_refptr<DecoderBuffer>& encrypted,
        const AudioDecodeCB& audio_decode_cb)
        = 0;
    virtual void DecryptAndDecodeVideo(
        const scoped_refptr<DecoderBuffer>& encrypted,
        const VideoDecodeCB& video_decode_cb)
        = 0;

    // Resets the decoder to an initialized clean state, cancels any scheduled
    // decrypt-and-decode operations, and fires any pending
    // AudioDecodeCB/VideoDecodeCB immediately with kError and NULL.
    // This method can only be called after the corresponding decoder has been
    // successfully initialized.
    virtual void ResetDecoder(StreamType stream_type) = 0;

    // Releases decoder resources, deinitializes the decoder, cancels any
    // scheduled initialization or decrypt-and-decode operations, and fires
    // any pending DecoderInitCB/AudioDecodeCB/VideoDecodeCB immediately.
    // DecoderInitCB should be fired with false. AudioDecodeCB/VideoDecodeCB
    // should be fired with kError.
    // This method can be called any time after Initialize{Audio|Video}Decoder()
    // has been called (with the correct stream type).
    // After this operation, the decoder is set to an uninitialized state.
    // The decoder can be reinitialized after it is uninitialized.
    virtual void DeinitializeDecoder(StreamType stream_type) = 0;

private:
    DISALLOW_COPY_AND_ASSIGN(Decryptor);
};

} // namespace media

#endif // MEDIA_BASE_DECRYPTOR_H_
